#include "text_query.h"
#include <iostream>

using namespace std;


TextQuery::TextQuery(std::ifstream &is)
    : file(new vector<string>)
{
    string text;
    while (getline(is, text)) {  // 对文件中的每一行
        file->push_back(text);  // 保存此行文本
        int n = file->size() - 1;  // 本行行号
        istringstream line(text);  // 将每行文本分解成单词
        string word;
        while (line >> word) {  // 对行中每个单词
            // 如果单词不在 wm 中，以之为下标在 wm 中添加一项
            auto &lines = wm[word];  // lines 是一个 shared_ptr
            if (!lines) {  // 在我们第一次遇到这个单词的时候，此指针为空
                lines.reset(new set<line_no>);  // 分配一个新的 set
            }
            lines->insert(n);  // 将此行号插入 set 中
        }
    }
}

QueryResult TextQuery::query(const std::string &sought) const
{
    // 如果未找到 sought,我们将返回一个指向此 set 的指针
    static shared_ptr<set<line_no>> nodata(new set<line_no>);
    // 使用 find 而不是下标运算符来查找单词，避免将单词添加到 wm 中
    auto loc = wm.find(sought);
    if (loc == wm.end()) {
        return QueryResult(sought, nodata, file);  // 未找到
    } else {
        return QueryResult(sought, loc->second, file);
    }
}

ostream& print(ostream &os, const QueryResult &qr)
{
    // 如果找到了单词，打印出现次数和所有出现的位置
    os << qr.sought << " occurs " << qr.lines->size() << " "
       << make_plural(qr.lines->size(), "time", "s") << endl;
    // 打印单词出现的每一行
    for (auto num : *qr.lines) {  // 对 set 中的每个单词
        // 避免行号从 0 开始给用户带来的困惑
        os << "\t(line " << num + 1 << " )"
           << *(qr.file->begin() + num) << endl;
        return os;
    }
}


void runQueries(ifstream &infile)
{
    // infile 是一个 ifstream,指向我们需要处理的文件
    TextQuery tq(infile);  // 保存文件并建立查询 map
    // 与用户交互：提示用户输入要查询的单词，完成查询并打印结果
    while (true) {
        cout << "enter word to look for, or q to quit: ";
        string s;
        // 若遇到文件尾或用户输入了 'q' 时循环终止
        if (!(cin >> s) || s == "q") {
            break;
        }
        // 指向查询并打印结果
        print(cout, tq.query(s)) << endl;
    }
}
